//import Vue from 'vue';
const caches = []
const queues = []
const locks = []
const NOOP = function () {}
const mergetObj = (a, b, del = true) => {
  if (del) {
    for (var k in a) {
      if (!b.hasOwnProperty(k)) {
        Vue.delete(a, k)
      }
    }
  }
  for (var p in b) {
    Vue.set(a, p, b[p])
  }
  return a
}

const checkPromise = (resolve, res) => {
  if (res instanceof Promise || typeof res.then === 'function') {
    res.then((res) => resolve(res))
  } else {
    resolve(res)
  }
}

//包裹一个函数，需要等待队列其他函数执行完，才可以执行
export function queueFn(key, fn, autoNext = true) {
  key = key + 'queueFn'
  if (!queues[key]) {
    queues[key] = {
      isLock: false,
      qs: []
    }
  }
  let qs = queues[key].qs
  let next = (isNext) => {
    if (isNext) {
      queues[key].isLock = false
    }
    if (!queues[key].isLock) {
      let q = qs.shift()
      if (q) {
        queues[key].isLock = true
        q().then((res) => {
          if (autoNext) {
            next(1)
          }
        })
      }
    }
  }
  let defer = deferPromise()
  qs.push(() => {
    //这里是传入next句柄，可以让用户手动调用next
    let res = fn((res) => {
      next(1)
    })
    //这里返回结果
    defer.resolve(res)
    return defer.promise
  })

  next()
  return defer.promise
}

//包裹一个函数，函数还没执行完不会再次执行
export function lockFn(key, fn) {
  key = key + 'lockFn'

  if (!locks[key]) {
    locks[key] = {
      isLock: false,
      fn
    }
  }
  if (locks[key].isLock) {
    return Promise.reject()
  } else {
    locks[key].isLock = true
    return fn().then((res) => {
      locks[key] = null
      return res
    })
  }
}

//包裹一个函数，函数返回的值缓存，并且在更新的时候保证所有引用的地方统一
export function cacheFn(key, fn, cache) {
  key = key + 'fn'
  if (!caches[key]) {
    caches[key] = {
      fn: fn,
      data: Vue.observable({})
    }
    cache = false
  }

  if (!cache) {
    let res = caches[key].fn()
    let data = caches[key].data
    if (res instanceof Promise || typeof res.then === 'function') {
      res = res.then((res) => {
        mergetObj(data, res)
        return data
      })
    } else {
      res = mergetObj(data, res)
    }
    caches[key].res = res
  }

  return caches[key].res
}

//包裹一个对象，可以修改对象的属性，并且在更新的时候保证所有引用的地方统一
export function cacheObj(key, data = null, del = true) {
  key = key + 'obj'
  if (!caches[key]) {
    caches[key] = {
      data: Vue.observable({})
    }
  }
  if (data) {
    let origin = caches[key].data
    mergetObj(origin, data, del)
  }
  return caches[key].data
}

export function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj))
}

export function deferPromise() {
  let _resolve, _reject
  let promise = new Promise((resolve, reject) => {
    _resolve = resolve
    _reject = reject
  })
  let subs = []
  let subscribe = (callback) => {
    subs.push(callback)
    return {
      unsubscribe: function () {
        let index = subs.indexOf(callback)
        if (index > -1) {
          subs.splice(index, 1)
        }
      }
    }
  }
  let _next = (res) => {
    subs.forEach((callback) => {
      callback(res)
    })
  }
  return {
    resolve: function (res) {
      _resolve(res)
    },
    reject: function (res) {
      _reject(res)
    },
    next: function (res) {
      _next(res)
    },
    then: (f1 = NOOP, f2 = NOOP) => {
      return promise.then(f1, f2)
    },
    catch: (callback) => {
      return promise.catch(callback)
    },
    promise,
    subscribe
  }
}

export function randomColor() {
  return '#' + ('00000' + ((Math.random() * 0x1000000) << 0).toString(16)).substr(-6)
}

export function hex2Rgba(bgColor, alpha = 1) {
  let rgba = _hex2Rgba(bgColor, alpha)
  return 'rgba(' + rgba.toString() + ')'
}

function _hex2Rgba(bgColor, alpha) {
  let color = bgColor.slice(1) // 去掉'#'号
  let rgba = [parseInt('0x' + color.slice(0, 2)), parseInt('0x' + color.slice(2, 4)), parseInt('0x' + color.slice(4, 6)), alpha]
  return rgba
}

export function hex2WebglColor(bgColor, alpha = 1.0) {
  let rgba = _hex2Rgba(bgColor, alpha)
  let [r, g, b, a] = rgba
  return [r / 255, g / 255, b / 255, a]
}

const getred = (color) => {
  const red = (color & 0xff0000) >> 16
  return red
}

const getgreen = (color) => {
  const green = (color & 0x00ff00) >> 8
  return green
}

const getblue = (color) => {
  const blue = color & 0x0000ff
  return blue
}

//十进制转hex
export function Rgb2Hex(color) {
  const r = getred(color)
  const g = getgreen(color)
  const b = getblue(color)
  const hex = '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
  return hex
}

//判断是否是JSON
export function isJSON(str) {
  if (typeof str == 'string') {
    try {
      var obj = JSON.parse(str)
      if (typeof obj == 'object' && obj) {
        return true
      } else {
        return false
      }
    } catch (e) {
      return false
    }
  }
  return false
}

//判断PC还是H5
var os = (function () {
  var ua = navigator.userAgent,
    isWindowsPhone = /(?:Windows Phone)/.test(ua),
    isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
    isAndroid = /(?:Android)/.test(ua),
    isFireFox = /(?:Firefox)/.test(ua),
    isChrome = /(?:Chrome|CriOS)/.test(ua),
    isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
    isPhone = /(?:iPhone)/.test(ua) && !isTablet,
    isPc = !isPhone && !isAndroid && !isSymbian
  return {
    isTablet: isTablet,
    isPhone: isPhone,
    isAndroid: isAndroid,
    isPc: isPc
  }
})()

export function colorHex(value) {
  var that = value
  //十六进制颜色值的正则表达式
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
  // 如果是rgb颜色表示
  if (/^(rgb|RGB)/.test(that)) {
    var aColor = that.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
    var strHex = '#'
    for (var i = 0; i < aColor.length; i++) {
      var hex = Number(aColor[i]).toString(16)
      if (hex.length < 2) {
        hex = '0' + hex
      }
      strHex += hex
    }
    if (strHex.length !== 7) {
      strHex = that
    }
    return strHex
  } else if (reg.test(that)) {
    var aNum = that.replace(/#/, '').split('')
    if (aNum.length === 6) {
      return that
    } else if (aNum.length === 3) {
      var numHex = '#'
      for (var i = 0; i < aNum.length; i += 1) {
        numHex += aNum[i] + aNum[i]
      }
      return numHex
    }
  }
  return that
}

export function colorRgb(value) {
  var sColor = value.toLowerCase()
  //十六进制颜色值的正则表达式
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
  // 如果是16进制颜色
  if (sColor && reg.test(sColor)) {
    if (sColor.length === 4) {
      var sColorNew = '#'
      for (var i = 1; i < 4; i += 1) {
        sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
      }
      sColor = sColorNew
    }
    //处理六位的颜色值
    var sColorChange = []
    for (var i = 1; i < 7; i += 2) {
      sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
    }
    return 'RGB(' + sColorChange.join(',') + ')'
  }
  return sColor
}

/**
 * HSL颜色值转换为RGB.
 * 换算公式改编自 http://en.wikipedia.org/wiki/HSL_color_space.
 * h, s, 和 l 设定在 [0, 1] 之间
 * 返回的 r, g, 和 b 在 [0, 255]之间
 *
 * @param   Number  h       色相
 * @param   Number  s       饱和度
 * @param   Number  l       亮度
 * @return  Array           RGB色值数值
 */
export function hslToRgb(h, s, l) {
  var r, g, b

  if (s == 0) {
    r = g = b = l // achromatic
  } else {
    var hue2rgb = function hue2rgb(p, q, t) {
      if (t < 0) t += 1
      if (t > 1) t -= 1
      if (t < 1 / 6) return p + (q - p) * 6 * t
      if (t < 1 / 2) return q
      if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
      return p
    }

    var q = l < 0.5 ? l * (1 + s) : l + s - l * s
    var p = 2 * l - q
    r = hue2rgb(p, q, h + 1 / 3)
    g = hue2rgb(p, q, h)
    b = hue2rgb(p, q, h - 1 / 3)
  }

  return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
}

/**
 * RGB 颜色值转换为 HSL.
 * 转换公式参考自 http://en.wikipedia.org/wiki/HSL_color_space.
 * r, g, 和 b 需要在 [0, 255] 范围内
 * 返回的 h, s, 和 l 在 [0, 1] 之间
 *
 * @param   Number  r       红色色值
 * @param   Number  g       绿色色值
 * @param   Number  b       蓝色色值
 * @return  Array           HSL各值数组
 */
export function rgbToHsl(r, g, b) {
  ;(r /= 255), (g /= 255), (b /= 255)
  var max = Math.max(r, g, b),
    min = Math.min(r, g, b)
  var h,
    s,
    l = (max + min) / 2

  if (max == min) {
    h = s = 0 // achromatic
  } else {
    var d = max - min
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
    switch (max) {
      case r:
        h = (g - b) / d + (g < b ? 6 : 0)
        break
      case g:
        h = (b - r) / d + 2
        break
      case b:
        h = (r - g) / d + 4
        break
    }
    h /= 6
  }

  return [h, s, l]
}

export function rgbToHsv(r, g, b) {
  r = r / 255
  g = g / 255
  b = b / 255
  var h, s, v
  var min = Math.min(r, g, b)
  var max = (v = Math.max(r, g, b))
  var l = (min + max) / 2
  var difference = max - min

  if (max == min) {
    h = 0
  } else {
    switch (max) {
      case r:
        h = (g - b) / difference + (g < b ? 6 : 0)
        break
      case g:
        h = 2.0 + (b - r) / difference
        break
      case b:
        h = 4.0 + (r - g) / difference
        break
    }
    h = Math.round(h * 60)
  }
  if (max == 0) {
    s = 0
  } else {
    s = 1 - min / max
  }
  s = Math.round(s * 100)
  v = Math.round(v * 100)
  return [h, s, v]
}

// 参数arr的3个值分别对应[h, s, v]
export function hsvToRgb(arr) {
  var h = arr[0],
    s = arr[1],
    v = arr[2]
  s = s / 100
  v = v / 100
  var r = 0,
    g = 0,
    b = 0
  var i = parseInt((h / 60) % 6)
  var f = h / 60 - i
  var p = v * (1 - s)
  var q = v * (1 - f * s)
  var t = v * (1 - (1 - f) * s)
  switch (i) {
    case 0:
      r = v
      g = t
      b = p
      break
    case 1:
      r = q
      g = v
      b = p
      break
    case 2:
      r = p
      g = v
      b = t
      break
    case 3:
      r = p
      g = q
      b = v
      break
    case 4:
      r = t
      g = p
      b = v
      break
    case 5:
      r = v
      g = p
      b = q
      break
    default:
      break
  }
  r = parseInt(r * 255.0)
  g = parseInt(g * 255.0)
  b = parseInt(b * 255.0)
  return [r, g, b]
}

export function rgbaToHex(rgba) {
  if (rgba && rgba.indexOf('rgba') > -1) {
    var values = rgba
      .replace(/rgba?\(/, '')
      .replace(/\)/, '')
      .replace(/[\s+]/g, '')
      .split(',')

    let hex = '#'
    values[3] = Math.floor(values[3] * 255)
    for (const i of values) {
      hex += Number(i).toString(16).padStart(2, '0')
    }
    return hex
  } else {
    return rgba
  }
}

export function trackGlobalVar(cb) {
  // 监控全局变量的创建
  const originalDefineProperty = Object.defineProperty
  Object.defineProperty = function (obj, prop, descriptor) {
    // console.log(obj, prop)
    cb(obj, prop)
    return originalDefineProperty.call(this, obj, prop, descriptor)
  }
}

/**
 *
 * 监听对象变化
 * @param {*} originalObj
 * @param {*} callback
 * @returns
 */
export function createTrackedObject(originalObj, callback) {
  return new Proxy(originalObj, {
    set(target, property, value, receiver) {
      callback(target, property, value)
      return Reflect.set(target, property, value, receiver)
    }
  })
}
